package com.chinamsp.dydb.dbsource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import com.chinamsp.baisc.util.ApplicationConstants;
import com.chinamsp.dydb.annotation.DbModule;


/**
 * 动态数据源 切换数据源
 * @author shifenghu
 *
 */
@Aspect
@Order(0)// 保证该AOP在@Transactional之前执行
@Component
public class DynamicDataSourceAspect {
	
	@Autowired
	private DataSourceManager dataSourceManager;

	@Before("execution(* " + ApplicationConstants.SCAN_PACKAGE_NAME + "..*.*Biz.*(..))")
    public void changeDataSource(JoinPoint joinPoint) throws Throwable {
		Class<?> bizClass;
		if (AopUtils.isAopProxy(joinPoint.getTarget())) {
			if (AopUtils.isCglibProxy(joinPoint.getTarget())) {
				bizClass = ClassUtils.getUserClass(joinPoint.getTarget());
			}else {
				bizClass = getJdkDynamicProxyTargetObject(joinPoint.getTarget());
			}
		}else {
			bizClass = joinPoint.getTarget().getClass();
		}
		// 获取 db module 
		DbModule dbModule = AnnotationUtils.findAnnotation(bizClass, DbModule.class);
		// 如果为空，则设置为默认
		if (dbModule == null) {
			DynamicDataSourceContextHolder.push(dataSourceManager.getDefaultSourceName(), DynamicDataSourcePolicyType.RANDOM , true);
		}else {
			DynamicDataSourceContextHolder.push(StringUtils.isEmpty(dbModule.name()) ? dataSourceManager.getDefaultSourceName() : dbModule.name(), dbModule.policy(), true);
		}
		
		logger.debug("method=" + bizClass.getName() + ", source is " + DynamicDataSourceContextHolder.getDataSource().getUrl());
    }

    @After("execution(* " + ApplicationConstants.SCAN_PACKAGE_NAME + "..*.*Biz.*(..))")
    public void restoreDataSource(JoinPoint joinPoint) {
        DynamicDataSourceContextHolder.pop();
    }
    
    /**
     * 获取 jdk class
     * @param proxy
     * @return
     * @throws Exception
     */
    private static Class<?> getJdkDynamicProxyTargetObject(Object proxy) throws Exception { 
    		Class<?>[] interfaces = proxy.getClass().getInterfaces();
    		return  interfaces != null && interfaces.length > 0 ? interfaces [0] : null;
    }  

	
	/**
	 * 根据 db module 获取 name
	 * @param dbModule
	 * @return
	 */
	public String getModuleName(DbModule dbModule) {
		return StringUtils.isEmpty(dbModule.name()) ? dbModule.value() : dbModule.name();
	}
	
	private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
}